package com.study.www.config;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.mongodb.Block;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Sorts;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 * @author : Administrator.zhuyanpeng
 * @date : 2019/10/28 - 17:02
 */
@Component
public class MongoPageHelper {

    // 最小页码
    public static final int FIRST_PAGE_NUM = 1;
    /** mongodb自带得id */
    public static final String MONGO_ID = "_id";

    @Autowired
    private  MongoTemplate mongoTemplate;
    @Autowired
    private MongoConverter mongoConverter;

    @Autowired
    public MongoPageHelper(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }


    /**
     * 分页查询，不考虑条件分页，直接使用skip-limit来分页.
     *
     */
    public <T> PageResult<T> pageQuery(Bson queryBson, Class<T> clazz,Integer pageNum, Integer pageSize) {
        return pageQuery(queryBson, clazz,pageNum, pageSize, null,null);
    }


    public <T> PageResult<T> pageQuery(Bson queryBson, Class<T> clazz,Integer pageNum, Integer pageSize,String lastId) {
        return pageQuery(queryBson, clazz,pageNum, pageSize, lastId,null);
    }

    public <T> PageResult<T> pageQuery(Bson queryBson, Class<T> clazz,Integer pageNum, Integer pageSize,Document selectDocument) {
        return pageQuery(queryBson, clazz,pageNum, pageSize, null,selectDocument);
    }

    /**
     * 分页查询.
     *
     * @param queryBson Bson，构造你自己的查询条件.
     * @param clazz Mongo collection定义的 class，用来确定查询哪个集合.
     * @param pageSize 分页的大小.
     * @param pageNum 当前页.
     * @param lastId 条件分页参数, 区别于skip-limit，采用find(_id>lastId).limit分页.
     * 如果不跳页，像朋友圈，微博这样下拉刷新的分页需求，需要传递上一页的最后一条记录的ObjectId。 如果是null，则返回pageNum那一页.
     * @param <T> collection定义的class类型.
     * @param  selectDocument 查询返回的字段组.
     * @return PageResult，一个封装page信息的对象.
     */
    public <T> PageResult<T> pageQuery(Bson queryBson, Class<T> clazz,Integer pageNum, Integer pageSize,String lastId,Document selectDocument) {
        //分页逻辑
        MongoCollection<Document> collection = mongoTemplate.getCollection(Objects.requireNonNull(TableUtils.getTableName(clazz)));
        long total = collection.countDocuments(queryBson);
        final PageResult<T> pageResult = new PageResult<>();
        pageResult.setTotal(total);
        pageResult.setPageSize(pageSize);
        pageResult.setPageNum(pageNum);
        //总页数
        final Integer pages = (int) Math.ceil(total / (double) pageSize);
        if (pageNum <= 0) {
            pageNum = FIRST_PAGE_NUM;
        }
        // 如果查询页数大于总页数则为空
        if (pageNum > pages){
            pageResult.setList(Lists.newArrayList());
            return pageResult;
        }
        FindIterable<Document> findIterable = null;
        //默认根据id 排序
        Bson mongoIdAscBson = Sorts.orderBy(Sorts.ascending(MONGO_ID));
        if (StringUtils.isNotBlank(lastId)) {
            if (pageNum != FIRST_PAGE_NUM) {
                Bson lastIdBson = Filters.gt(MONGO_ID, new ObjectId(lastId));
                queryBson =Filters.and(queryBson, lastIdBson);
            }
            findIterable = collection.find(queryBson).sort(mongoIdAscBson);
        } else {
            int skip = pageSize * (pageNum - 1);
            findIterable = collection.find(queryBson).sort(mongoIdAscBson).skip(skip);
        }
        findIterable = findIterable.limit(pageSize);
        if (!ObjectUtils.isEmpty(selectDocument)) {
            findIterable.projection(selectDocument);
        }
        MongoCursor<Document> iterator = findIterable.iterator();
        List<T> list = Lists.newArrayList();
        while (iterator.hasNext() ){
            Document next = iterator.next();
            if (!ObjectUtils.isEmpty(next.get(MONGO_ID))) {
                next.put("id",next.get(MONGO_ID).toString());
            }
            list.add(mongoConverter.read(clazz,next));
        }
        pageResult.setList(list);
        return pageResult;
    }
}
